package qos.estimator.statistics;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.concurrent.Semaphore;

import qos.estimator.exception.CollectorException;

public class CPUStatisticsCollector implements IStatisticsCollector {
	
	private boolean forceStop = false;
	private Semaphore semaphore = new Semaphore(1);
	private Map<String, Double>cpuUtilization = new HashMap<String, Double>();
	private CPUCollectorStrategy collectorStrategy;
	
	public CPUStatisticsCollector() {
		new Thread(new Runnable(){
			public void run() {
				try{
					Process process = Runtime.getRuntime().exec("mpstat -I SUM -u 5");
					java.io.BufferedReader in = new java.io.BufferedReader(new java.io.InputStreamReader(process.getInputStream()));
					String line = null;  
					while ((line = in.readLine()) != null) {
						if(forceStop)
							return;
						StringTokenizer st = new StringTokenizer(line, " ");
						//ignoring the first two columns (time and 'CPU')
						if(!st.hasMoreTokens())
							continue;
						st.nextToken();
						String header = st.nextToken();
						//prevents problems on computers with time in 12-hours format.
						if(header.equals("PM") || header.equals("AM")){
							st.nextToken();
						}
						header = st.nextToken();
						
						if(header.equals("%usr")){
							collectorStrategy = new CPUPercentageCollectorStrategy();
							continue;
						} else if(header.equals("intr/s")){
							collectorStrategy = new CPUInterruptionsPerSecondStrategy();
							continue;
							//This verification below is necessary to avoid an exception from being thrown, 
							// as the first line is not a digit at the third column. 
						} else if (Character.isDigit(header.charAt(0))){
							semaphore.acquire();
							collectorStrategy.extract(header, st, cpuUtilization);
							semaphore.release();
						}
					}
				}catch (IOException e) {
					e.printStackTrace();
				} catch (InterruptedException e) {
					e.printStackTrace();
				} finally{
					semaphore.release();
				}
			}
		}).start();
	}
	
	public void forceStop() {
		forceStop = true;
	}

	public Map<String, Double> next() throws CollectorException {
		try {
			semaphore.acquire();
			Map<String, Double> nonVolatileMap = new HashMap<String, Double>(cpuUtilization);
			return nonVolatileMap;
		} catch (InterruptedException e) {
			e.printStackTrace();
			throw new CollectorException(e);
		} finally {
			semaphore.release();
		}
		
	}
	
	public static void main(String[] args) throws Exception {
		CPUStatisticsCollector cpuStatisticsCollector = new CPUStatisticsCollector();
		for (int i = 0; i < 20; i++) {
			Map<String, Double> cpuUtilization = (Map<String, Double>) cpuStatisticsCollector.next();
			
			for (String measure : cpuUtilization.keySet()) {
				System.out.println("Measure: "+measure +": "+cpuUtilization.get(measure));
			}
			Thread.sleep(2000);
		}
		cpuStatisticsCollector.forceStop();
	}

}
